package benny.ApkposStore.utils;


/***
 *  使用例子，可以上传二进制和其他参数
 * 	BinUploader binUploader = new BinUploader();
 *  binUploader.setMultiPart("keyA", "a");
 *  binUploader.setMultiPart("keyb", "b");
 *  binUploader.setMultiPart("keyc", "c");
 *  binUploader.setUploadUrl("http://58.215.189.116/wsgi/uploadtest");
 *  		
 *  String content = "this is binary data";
 *  binUploader.setBinary(content.getBytes());
 *  
 *  byte[] respone = binUploader.upload();
 *  if(response != null) {
 *  	//TODO:成功返回应答
 *  }
 *  else {
 *  	//TODO:上传不成功
 *  }
 * @author bbg
 *
 */

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;

import org.apache.http.util.ByteArrayBuffer;

import android.text.TextUtils;
import android.util.Log;


public class BinUploader {
	private HashMap<String, String> mMultiPart = new HashMap<String, String>();
	private byte[] mBinaryContent;
	private String mFileName = "protocolbuf_binary";
	private String mUploadUrl = "";
	private String mBoundary = "734774uern5jdhfkgsdnvrwpu8663944586cbzxbsyyq3we79879";
	private String tag = "BinUploader";
	
	public void setMultiPart(String key, String value) {
		mMultiPart.put(key, value);
	}
	
	public void setBinary(byte[] content) {
		mBinaryContent = content;
	}
	
	public void setUploadUrl(String url) {
		mUploadUrl = url;
	}
	
	/**
	 * 执行同步上传，并返回应答信息，应该放到异步框架里取完成这种任务
	 * @return
	 */
	public byte[] upload() {
		HttpURLConnection conn = null;
		URL url;
		try {
			url = new URL(mUploadUrl);
			conn = (HttpURLConnection) url.openConnection();
			
			conn.setConnectTimeout(60000);
			conn.setReadTimeout(60000);
			
			conn.setDoInput(true);
			conn.setDoOutput(true);
			conn.setUseCaches(false);				
			
			conn.setRequestMethod("POST");
			conn.setRequestProperty("Content-Type", "multipart/formdata; boundary=" + mBoundary);
			conn.addRequestProperty("Accept-Encoding", "gzip,deflate");
			
			DataOutputStream outStream = null;
			outStream = new DataOutputStream(conn.getOutputStream());
			outStream.write(makeMultiPartString().getBytes());
			writeBinary(outStream);
			writeFinallyBoundary(outStream);
			outStream.flush();
			
			int retCode = conn.getResponseCode();
			if(retCode == 200) {
				String encode = conn.getContentEncoding();
				byte[] response = inputStream2ByteArray(conn.getInputStream(), encode);
				
				return response;
			}
			
		} catch (MalformedURLException e1) {
			Log.e(tag, e1.getMessage());
		}catch (ProtocolException e) {
			Log.e(tag, e.getMessage());
		} catch (IOException e) {
			Log.e(tag, e.getMessage());
		}
		return null;
	}
	
    private String makeMultiPartString(){
    	String buf = "";
    	Iterator<?> iter = mMultiPart.entrySet().iterator(); 
    	while (iter.hasNext()) { 
			@SuppressWarnings("unchecked")
			HashMap.Entry<String, String> entry = (HashMap.Entry<String, String>) iter.next();
    	    Object key = entry.getKey(); 
    	    Object val = entry.getValue();
    	    
    	    buf += "--" + mBoundary + "\r\n" 
        			+ "Content-Disposition: form-data; name=\""+ key.toString() + "\""
        			+ "\r\n"
        			+ "Content-Type: text/plain"
        			+ "\r\n\r\n"
        			+ val.toString()
        			+ "\r\n";
    	    
    	} 

    	return buf;
    }
    
    private void writeBinary(DataOutputStream outStream) throws IOException {
    	String buf =  "--" + mBoundary + "\r\n" 
    			+ "Content-Disposition: form-data; name=\"binary\"; filename=\""+ mFileName +"\""
    			+ "\r\n"
    			+ "Content-Type: application/octet-stream"
    			+ "\r\n\r\n";
    	
    	outStream.write(buf.getBytes());
    	outStream.write(mBinaryContent);
    	
    	String a = "\r\n";
    	outStream.write(a.getBytes());
    	
    }
    
    private void writeFinallyBoundary(DataOutputStream outStream) throws IOException {
    	String buf = "--" + mBoundary + "--";
    	outStream.write(buf.getBytes());
    }   
    
    /**
     * 将流转换成字节数组
     * @param connectEncode http回应中的 content-type字段的值
     * @throws IOException
     */
    public static byte[] inputStream2ByteArray(InputStream input,
        String connectEncode) throws IOException {

        if (input == null) {
            return null;
        }
        InputStream inputStream = null;
        if (!TextUtils.isEmpty(connectEncode) && connectEncode.contains("gzip")) {
            inputStream = new GZIPInputStream(input);
        } else {
            inputStream = input;
        }
        
        ByteArrayBuffer bytes = new ByteArrayBuffer(20 * 1024);

        byte[] buf = new byte[20 * 1024];
        int len = 0;

        try {
            while ((len = inputStream.read(buf)) != -1) {
                bytes.append(buf, 0, len);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
      
        return bytes.toByteArray();
    }
	
    
    public static String inputStream2String(InputStream inputStream,
            String connectEncode, String streamEncode) throws IOException {
            BufferedReader bufReader = null;

            if (!TextUtils.isEmpty(connectEncode) && connectEncode.contains("gzip")) {
                bufReader = new BufferedReader(new InputStreamReader(
                    new GZIPInputStream(inputStream), streamEncode));
            } else {
                bufReader = new BufferedReader(new InputStreamReader(inputStream,
                    streamEncode));
            }

            StringBuilder response = new StringBuilder();
            String line = "";
            try {
                while ((line = bufReader.readLine()) != null) {
                    response.append(line);
                }
            } finally {
                if (bufReader != null) {
                    bufReader.close();
                }
            }
            return response.toString();
        }
}
